package com.by.datasource.monitor;

import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.stat.DruidStatManagerFacade;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@Slf4j
@Component
@ConditionalOnProperty(name = "by.datasource.monitor.enabled", havingValue = "true")
public class DruidPoolLogSupport {

    private static final String PRETTY_TEMPLATE = "{}:[{}] ";

    private static final List<String> PRINT_PROPERTIES = Lists.newArrayList(
            "WaitThreadCount",
            "NotEmptyWaitCount",
            "NotEmptyWaitMillis",
            // 连接池中当前活动的连接数、最大连接数以及达到此最大值的时间点
            "PoolingCount",
            "PoolingPeak",
            "PoolingPeakTime",
            // 当前正在使用中的连接数量和达到峰值时的连接数量，以及达到此峰值的时间点
            "ActiveCount",
            "ActivePeak",
            "ActivePeakTime",
            "InitialSize",
            "MinIdle",
            "MaxActive"
    );

    private static final StringBuilder PRETTY_PRINT = new StringBuilder();

    @Scheduled(cron = "${by.datasource.monitor.cron}")
    public void print() {
        printDruidPoolStat();
    }

    private void printDruidPoolStat() {
        List<Map<String, Object>> dataSourceStatDataList = DruidStatManagerFacade.getInstance().getDataSourceStatDataList();
        if (CollectionUtils.isEmpty(dataSourceStatDataList)) {
            log.info("[DruidPoolLogSupport][printDruidPoolStat] dataSourceStatDataListIsNull");
            return;
        }

        dataSourceStatDataList.forEach(item -> {
            try {
                JSONObject jsonObject = new JSONObject(item);
                String dataSourceName = jsonObject.getString("Name");

                PRETTY_PRINT.setLength(0);
                PRINT_PROPERTIES.forEach(property -> {
                    String propertyVal = jsonObject.getString(property);
                    PRETTY_PRINT.append(StrUtil.format(PRETTY_TEMPLATE, property, propertyVal));
                });

                log.info("[DruidPoolLogSupport][printDruidPoolStat] dataSourceName:[{}] {}"
                        , dataSourceName, PRETTY_PRINT);
            } catch (Exception e) {
                log.warn("[DruidPoolLogSupport][printDruidPoolStat] recordDruidStatError:[{}] hasException:[{}] ", item, ExceptionUtils.getStackTrace(e));
            }
        });
    }

}
